/**
 * 
 */
package org.istt.web;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.servlet.ServletContext;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.WordUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang.time.DateUtils;
import org.apache.struts2.ServletActionContext;
import org.istt.domain.AttachFile;
import org.istt.domain.AttachFileDetail;
import org.istt.domain.Category;
import org.istt.domain.CategoryType;
import org.istt.domain.Department;
import org.istt.domain.DocumentType;
import org.istt.domain.Exchange;
import org.istt.domain.Field;
import org.istt.domain.File;
import org.istt.domain.FileBoSungCCHN;
import org.istt.domain.FileCapCCHN;
import org.istt.domain.FileCapCCMGBDS;
import org.istt.domain.FileCapLaiCCHN;
import org.istt.domain.FileCapPhepXayDung;
import org.istt.domain.FileDieuChinhGPXD;
import org.istt.domain.FileGiaHanCPXD;
import org.istt.domain.FileManagement;
import org.istt.domain.FileStatus;
import org.istt.domain.Group;
import org.istt.domain.SubCategory;
import org.istt.domain.TimeHoliday;
import org.istt.domain.TimeWeekend;
import org.istt.domain.User;
import org.istt.domain.Workflow;
import org.istt.domain.WorkflowProcess;
import org.istt.service.AttachFileDetailManager;
import org.istt.service.AttachFileManager;
import org.istt.service.CategoryManager;
import org.istt.service.CategoryTypeManager;
import org.istt.service.DepartmentManager;
import org.istt.service.DocumentTypeManager;
import org.istt.service.FieldManager;
import org.istt.service.FileBoSungCCHNManager;
import org.istt.service.FileCapCCHNManager;
import org.istt.service.FileCapCCMGBDSManager;
import org.istt.service.FileCapGPXDManager;
import org.istt.service.FileCapLaiCCHNManager;
import org.istt.service.FileDieuChinhGPXDManager;
import org.istt.service.FileGiaHanGPXDManager;
import org.istt.service.FileManager;
import org.istt.service.FileMgrManager;
import org.istt.service.FileStatusManager;
import org.istt.service.GroupManager;
import org.istt.service.SubCategoryManager;
import org.istt.service.TimeHolidayManager;
import org.istt.service.TimeWeekendManager;
import org.istt.service.UserManager;
import org.istt.service.WorkflowManager;
import org.istt.service.WorkflowProcessManager;
import org.istt.web.helper.ExtendedPaginatedList;
import org.joda.time.DateMidnight;
import org.joda.time.DateTime;
import org.joda.time.DateTimeConstants;
import org.joda.time.Hours;
import org.joda.time.MutableDateTime;
import org.springframework.beans.factory.annotation.Autowired;

import com.opensymphony.xwork2.ActionContext;

/**
 * @author Huy
 * 
 */
public class FileAction extends BaseAction<FileManager, File, String> {

	/**
	 * 
	 */
	private static final long serialVersionUID = 9012754123343759656L;
	private FieldManager fieldManager;
	private CategoryManager categoryManager;
	private FileMgrManager fileMgrManager;
	private WorkflowProcessManager wfpMgr;
	private CategoryTypeManager categoryTypeManager;
	private AttachFileManager attachFileManager;
	private DocumentTypeManager documentTypeManager;
	private UserManager userManager;
	
	private FileManagement fmgr;
	private String fromDate;
	private String toDate;
	private String fieldId;
	private String groupIdToExchange;
	private String groupIdToTransfer;
	private Field field;
	private String cateId;
	private String subCateId;
	private File file;
	private String id;
	private List<Exchange> exchanges;
	
	private String[] attachFileId;
	private String[] attachFileDetailId;
	private List<String> numberOfCopy;
	private String[] documentTypeId;
	private String[] checked;
	
	private List<WorkflowProcess> workflowProcesses;
	private List<Object[]> fileProcessVoucher;
	private GroupManager groupMgr;
	private String groupId;
	private String userId;
	private WorkflowManager workflowMgr;
	private DepartmentManager departmentManager;
	private String departmentId;
	private FileStatusManager fileStatusMgr;
	private String fileStatusId;
	private Double totalDayOfWork;
	
	private boolean ableToNextStep;
	private SubCategoryManager subCategoryManager;
	
	@Autowired
	private FileManager fileMgr;

	@Autowired
	private FileCapGPXDManager fileOnlineMgr;

	private int totalOverStep;
	
	public FileManager getFileMgr() {
		return fileMgr;
	}

	public void setFileMgr(FileManager fileMgr) {
		this.fileMgr = fileMgr;
	}

	public List<FileStatus> getFileStatuses() {
		return fileStatusMgr.getList();
	}

	@Autowired
	public void setFileStatusMgr(FileStatusManager fileStatusMgr) {
		this.fileStatusMgr = fileStatusMgr;
	}
	
	@Autowired
	public void setSubCategoryManager(SubCategoryManager subCategoryManager) {
		this.subCategoryManager = subCategoryManager;
	}

	public List<Department> getDepartments() {
		return departmentManager.getList();
	}
	
	@Autowired
	public void setDepartmentManager(DepartmentManager departmentManager) {
		this.departmentManager = departmentManager;
	}
	
	@Autowired
	public void setWorkflowMgr(WorkflowManager workflowMgr) {
		this.workflowMgr = workflowMgr;
	}

	public String getUserId() {
		return userId;
	}

	public void setUserId(String userId) {
		this.userId = userId;
	}
	
	public void setGroupId(String groupId) {
		this.groupId = groupId;
	}

	public String getGroupId() {
		return groupId;
	}
	
	public List<DocumentType> getDocumentTypes() {
		return documentTypeManager.getList();
	}
	
	@Autowired
	public void setDocumentTypeManager(DocumentTypeManager documentTypeManager) {
		this.documentTypeManager = documentTypeManager;
	}
	
	public String[] getAttachFileId() {
		return attachFileId;
	}

	public void setAttachFileId(String[] attachFileId) {
		this.attachFileId = attachFileId;
	}
	
	public String[] getAttachFileDetailId() {
		return attachFileDetailId;
	}

	public void setAttachFileDetailId(String[] attachFileDetailId) {
		this.attachFileDetailId = attachFileDetailId;
	}

	public List<String> getNumberOfCopy() {
		return numberOfCopy;
	}

	public void setNumberOfCopy(List<String> numberOfCopy) {
		this.numberOfCopy = numberOfCopy;
	}

	public String[] getDocumentTypeId() {
		return documentTypeId;
	}

	public void setDocumentTypeId(String[] documentTypeId) {
		this.documentTypeId = documentTypeId;
	}

	public String[] getChecked() {
		return checked;
	}

	public void setChecked(String[] checked) {
		this.checked = checked;
	}

	@Autowired
	public void setCategoryTypeManager(CategoryTypeManager categoryTypeManager) {
		this.categoryTypeManager = categoryTypeManager;
	}
	
	public List<CategoryType> getCategoryTypeList() {
		return categoryTypeManager.getList();
	}
	
	public void setSaveExchangeMessage() {
		ActionContext.getContext().getSession()
				.put("message", getText("exchange.saved"));
	}	


	/**
	 * @param id
	 *            the id to set
	 */
	public void setId(String id) {
		this.id = id;
	}
	
	/**
	 * @param workflowProcessManager the workflowProcessManager to set
	 */
	@Autowired
	public void setWorkflowProcessManager(
			WorkflowProcessManager wfpMgr) {
		this.wfpMgr = wfpMgr;
	}

	/**
	 * @param fileMgrManager the fileMgrManager to set
	 */
	@Autowired
	public void setFileMgrManager(FileMgrManager fileMgrManager) {
		this.fileMgrManager = fileMgrManager;
	}
	
	@Autowired
	public void setAttachFileManager(AttachFileManager attachFileManager) {
		this.attachFileManager = attachFileManager;
	}

	public Field getField() {
		return field;
	}
	
	public void setFile(File file) {
		this.file = file;
	}
	
	/**
	 * @return the file
	 */
	public File getFile() {
		if (entity!= null && entity.getId() != null) {
			return entity;
		}
		return file;
	}
	
	/**
	 * @return the cateId
	 */
	public String getCateId() {
		if (StringUtils.isEmpty(cateId) && entity!= null && entity.getId() != null) {
			return cateId = entity.getCategory().getId() + "";
		}
		return cateId;
	}

	/**
	 * @param cateId
	 *            the cateId to set
	 */
	public void setCateId(String cateId) {
		this.cateId = cateId;
	}
	
	public void setSubCateId(String subCateId) {
		this.subCateId = subCateId;
	}
	
	public String getSubCateId() {
		if (StringUtils.isEmpty(subCateId) && entity!= null && entity.getId() != null) {
			return subCateId = entity.getSubCategory().getId() + "";
		}
		return subCateId;
	}

	
	/**
	 * @return the fieldId
	 */
	public String getFieldId() {
		// fieldID has selected on form
		if (StringUtils.isEmpty(fieldId) && entity!= null && entity.getId() != null) {
			return fieldId = entity.getCategory().getField().getId() + "";
		}
		// Load the first time enter form
		else{
			Field field = fieldManager.getFieldByDepartment(loggedUser.getDepartment().getId());
			if(field != null && field.getId()!=null)
				return fieldId = field.getId().toString();
		}
		return fieldId;
	}

	/**
	 * @param fieldId
	 *            the fieldId to set
	 */
	public void setFieldId(String fieldId) {
		this.fieldId = fieldId;
	}

	/**
	 * @return the fromDate
	 */
	public String getFromDate() {
		return fromDate;
	}

	/**
	 * @param fromDate
	 *            the fromDate to set
	 */
	public void setFromDate(String fromDate) {
		this.fromDate = fromDate;
	}

	/**
	 * @return the toDate
	 */
	public String getToDate() {
		return toDate;
	}

	/**
	 * @param toDate
	 *            the toDate to set
	 */
	public void setToDate(String toDate) {
		this.toDate = toDate;
	}

	/**
	 * @return the fields
	 */
	public List<Field> getFields() {
		return fieldManager.getList();
	}

	/**
	 * @param fieldManager
	 *            the fieldManager to set
	 */
	@Autowired
	public void setFieldManager(FieldManager fieldManager) {
		this.fieldManager = fieldManager;
	}

	/**
	 * @param categoryManager
	 *            the categoryManager to set
	 */
	@Autowired
	public void setCategoryManager(CategoryManager categoryManager) {
		this.categoryManager = categoryManager;
	}
	
	/**
	 * @return the catList
	 */
	public List<NameValuePair> getCatList() {
		List<NameValuePair> catList = new ArrayList<NameValuePair>();
		if (!StringUtils.isEmpty(fieldId)) {
			if (log.isDebugEnabled()) {
				log.debug("fieldId is equal to " + fieldId
						+ " getting categories");
			}

		List<Category> categories = categoryManager.getByFieldId(NumberUtils
					.toLong(fieldId));
			for (Category c : categories) {
				NameValuePair elm = new NameValuePair();
				
				if(StringUtils.length(c.getCategoryName()) > 80)
					elm.setName(StringUtils.substring(c.getCategoryName(), 0, 80) + "...");
				else
					elm.setName(StringUtils.substring(c.getCategoryName(), 0, 80));
				
				elm.setValue(c.getId() + "");
				catList.add(elm);
			}
		}
		return catList;
	}
	
	
	
	/**
	 * @return the catList
	 */
	public List<NameValuePair> getSubCateList() {
		List<NameValuePair> catList = new ArrayList<NameValuePair>();
		if (!StringUtils.isEmpty(cateId)) {
			if (log.isDebugEnabled()) {
				log.debug("cateId is equal to " + cateId
						+ " getting sub categories");
			}
			
			List<SubCategory> subCategories = subCategoryManager.findByCategoryId(NumberUtils
					.toLong(cateId));
			for (SubCategory c : subCategories) {
				NameValuePair elm = new NameValuePair();
				elm.setName(c.getName());
				elm.setValue(c.getId() + "");
				catList.add(elm);
			}
		}
		return catList;
	}
	
	public String view() {
		return SUCCESS;
	}
	
	public ExtendedPaginatedList getHistoryList(){
		ExtendedPaginatedList paginatedList = paginateListFactory.getPaginatedListFromRequest(ServletActionContext.getRequest());
		
		if(StringUtils.isNotEmpty(fromDate) && StringUtils.isNotEmpty(toDate)){
			Date f;
			Date t;
			try {
				f = StringUtils.isEmpty(fromDate) ? null : DateUtils.parseDate(
						fromDate, new String[] { getText("date.format") });
				
				t = StringUtils.isEmpty(toDate) ? null : DateUtils.parseDate(
						toDate, new String[] { getText("date.format") });
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				
				f = new Date();
				t = new Date();
			}
			
			return this.fileMgr.getHistoryByUser(loggedUser.getId(), f, t,paginatedList);
		}else{
			return this.fileMgr.getHistoryByUser(loggedUser.getId(), new Date(), new Date(),paginatedList);
		}
		
	}

	public List<Group> getListGroup() {
		return groupMgr.getList();
	}
	
	private List<AttachFileDetail> listAttachFile;

	private List<AttachFileDetail> listAttachByFile;
	

	public List<NameValuePair> getListUserForExchange() {
		/*
		 * List<NameValuePair> lstUser = new ArrayList<NameValuePair>(); return
		 * lstUser;
		 */
		List<NameValuePair> lstUser = new ArrayList<NameValuePair>();
		if (!StringUtils.isEmpty(groupIdToExchange)) {
			if (log.isDebugEnabled()) {
				log.debug("groupIdToExchange is equal to " + groupIdToExchange + " getting users");
			}
			List<User> lstUsers = new ArrayList<User>();
			lstUsers = userManager.findUserByDeptId(NumberUtils.toLong(groupIdToExchange));
			for (User u : lstUsers) {
				NameValuePair elm = new NameValuePair();
				elm.setName(u.getFullname());
				elm.setValue(u.getId() + "");
				lstUser.add(elm);
			}
		}
		return lstUser;
	}
	
	public List<NameValuePair> getListUserForTransfer() {
		/*
		 * List<NameValuePair> lstUser = new ArrayList<NameValuePair>(); return
		 * lstUser;
		 */
		List<NameValuePair> lstUser = new ArrayList<NameValuePair>();
		if (!StringUtils.isEmpty(groupIdToTransfer)) {
			if (log.isDebugEnabled()) {
				log.debug("groupIdToTransfer is equal to " + groupIdToTransfer + " getting users");
			}
			List<User> lstUsers = new ArrayList<User>();
			lstUsers = userManager.findUserByDeptId(NumberUtils.toLong(groupIdToTransfer));
			for (User u : lstUsers) {
				NameValuePair elm = new NameValuePair();
				elm.setName(u.getFullname());
				elm.setValue(u.getId() + "");
				lstUser.add(elm);
			}
		}
		return lstUser;
	}
	
	private DateTime getCurrentDatetime(){
		
		Calendar input_time = Calendar.getInstance();
		Calendar input_date = Calendar.getInstance();
		
		DateTime currentTime = new DateTime();
		input_time.setTime(currentTime.toDate());
		
		DateTime inputDateTime = file.getInputDate();
		input_date.setTime(inputDateTime.toDate());
		
		return new DateTime(input_date.get(Calendar.YEAR),input_date.get(Calendar.MONTH)+1,input_date.get(Calendar.DAY_OF_MONTH),
				input_time.get(Calendar.HOUR_OF_DAY),input_time.get(Calendar.MINUTE));
	}
	
	@Override
	public File getEntity() {
		if (file != null) {
			// Update Id to File
			this.id = getId();
			
			// Update Subcategory
			Category tmpCategory = categoryManager.get(NumberUtils.toLong(cateId));
			if(StringUtils.isNotEmpty(subCateId) && !"0".equals(subCateId)){
				SubCategory stmp = subCategoryManager.get(NumberUtils.toLong(subCateId));
				file.setSubCategory(stmp);
			}
			
			// Update thu tuc hanh chinh
			file.setCategory(tmpCategory);
			ServletContext servletContext = ServletActionContext.getServletContext();
			int reportStartingPoint = NumberUtils.toInt((String)servletContext.getInitParameter("reportStartingPoint"));
			if (StringUtils.isNotEmpty(id)){
				//((FileManager)mgr).removeAttachFileDetail(id);
				
				//Chi update file-number khi chua dc gan so
				
				if(file.getNumber() != null && file.getNumber() != 0){
					// Not to do
				}else{
					
					if (DateTime.now().dayOfMonth().get() == reportStartingPoint 
							&& ((FileManager) mgr).getNumberOfFileOnDateReport(tmpCategory.getField().getId(),reportStartingPoint) == 0) {
						file.setNumber(1);
					} else {
						file.setNumber(((FileManager) mgr).getMaxNumberNoOfFile(tmpCategory.getField().getId(),reportStartingPoint) + 1);
					}
				}
			} else {
				if (log.isDebugEnabled()) {
					log.debug("setting new Id");
				}
				
				//Updated by NDTHO.2012.03.01: change format of ID = yyyyMMddHHmm (12 characters)
				id = new StringBuilder(new SimpleDateFormat("yyMMddHHmm").format(new Date())).toString();
				
				if (DateTime.now().dayOfMonth().get() == reportStartingPoint 
						&& ((FileManager) mgr).getNumberOfFileOnDateReport(tmpCategory.getField().getId(),reportStartingPoint) == 0) {
					file.setNumber(1);
				} else {
					file.setNumber(((FileManager) mgr).getMaxNumberNoOfFile(tmpCategory.getField().getId(),reportStartingPoint) + 1);
				}
			}
			// Cap nhat File ID
			file.setId(id);
			
			// Ngay tiep nhan ho so
			file.setInputDate(getCurrentDatetime());
			
			// Nguoi nop ho so
			file.setSender(WordUtils.capitalizeFully(file.getSender()));

			// Thong tin lien he
			file.setContactName(WordUtils.capitalizeFully(file.getContactName()));
			
			// Danh sach ho so dinh kem
			/*if (attachFileId != null) {
				for (int i = 0; i < attachFileId.length; i++) {
					//AttachFile af = attachFileManager.getAttachFile(attachFileId[i]);
					AttachFile af = new AttachFile();
					af.setId(NumberUtils.toLong(attachFileId[i]));
					
					DocumentType dt = new DocumentType();
					dt.setId(NumberUtils.toLong(documentTypeId[i]));
					
					try {
						AttachFileDetail detail = new AttachFileDetail();
						if (attachFileDetailId != null) {
							detail.setId(NumberUtils.toLong(attachFileDetailId[i]));
						}
						detail.setAttachFile(af);
						detail.setFile(file);
						detail.setNumberOfcopy(NumberUtils.toLong(numberOfCopy.get(i)));
						detail.setDocumentType(dt);
						
						if("true".equals(checked[i])){
							file.addAttachFileDetail(detail);
							
						} else if("false".equals(checked[i])) {
							file.removeAttachFileDetail(detail);
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}*/
			
			// Nguoi tiep nhan ho so
			file.setCreatedBy(loggedUser);
			
			/*CAP NHAT DANH SACH GIAY TO DI KEM HO SO*/
			updateAttachFile();
			
	        int tofmgr = fileMgrManager.countByFileId(file.getId());
	        
	        // Cap nhat du lieu vao bang TBL_FILE_MANAGEMENT
	        if (tofmgr == 0) {
	        	fmgr = new FileManagement();
		        fmgr.setReceivedDate(getCurrentDatetime());
		        fmgr.setSender(loggedUser);
		        fmgr.setApprover(loggedUser);
		        fmgr.setWorkflowProcess(wfpMgr.getFirstStepOfWorkflow(file.getCategory().getWorkflow().getId()));
		        fmgr.setActiveStatus(false);
		        fmgr.setViewStatus(false);
	        }
		}
		return file;
	}
	
	@Autowired
	private AttachFileDetailManager attDetailManager;
	
	private void updateAttachFile(){
		log.debug("Enter method updateAttachFile...");
		
		/*CAP NHAT DANH SACH GIAY TO DI KEM HO SO*/
		if (attachFileId != null) {
			log.debug("Total attach file: "+attachFileId.length);
			for (int i = 0; i < attachFileId.length; i++) {
				AttachFile af = new AttachFile();
				af.setId(NumberUtils.toLong(attachFileId[i]));
				
				try {
					DocumentType dt = new DocumentType();
					dt.setId(NumberUtils.toLong(documentTypeId[i]));
					
					AttachFileDetail attachFileDetail = new AttachFileDetail();
					if(attachFileDetailId!=null && StringUtils.isNotEmpty(attachFileDetailId[i])){
						attachFileDetail = attDetailManager.getById(NumberUtils.toLong(attachFileDetailId[i]));
					}
					attachFileDetail.setNumberOfcopy(NumberUtils.toLong(numberOfCopy.get(i)));
					attachFileDetail.setDocumentType(dt);
					
					attachFileDetail.setAttachFile(af);
					attachFileDetail.setFile(file);
					
					
					if("true".equals(checked[i])){
						file.addAttachFileDetail(attachFileDetail);
					} else if("false".equals(checked[i])) {
						if(attachFileDetailId!=null && StringUtils.isNotEmpty(attachFileDetailId[i]))
							attDetailManager.removeAttachFileDetail(attachFileDetail.getId());
						
						file.removeAttachFileDetail(attachFileDetail);
					}
					
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	@Override
	public String getId() {
		return file==null? id : file.getId();
	}
	
	public boolean isValid() {
		Category cat = categoryManager.get(NumberUtils.toLong(cateId));
		return cat != null && !StringUtils.isEmpty(cat.getCode());
	}
	
	public boolean isNumberOfCopyValid() {
		boolean isValid = true;
		if (!CollectionUtils.isEmpty(numberOfCopy)) {
			for (int i = 0; i < numberOfCopy.size(); i++) {
				if (NumberUtils.toFloat(numberOfCopy.get(i)) == 0.0f) {
					isValid = false;
					break;
				}
			}
		} else {
			isValid = false;
		}
		return isValid;
	}
	
	public boolean isOutputDateValid() {
		if (file.getOutputDate() == null) return true;
		Category ct = categoryManager.get(NumberUtils.toLong(cateId));
		if (ct == null) {
			return false;
		} else {
			totalDayOfWork = workflowMgr.getTotalDayOfWork(ct.getWorkflow().getId());
			DateTime input = getNow();
			if(file.getInputDate()!=null)
				input = file.getInputDate();
			
			if (Double.valueOf(
//					Hours.hoursBetween(getNow(), file.getOutputDate()).getHours()).doubleValue()/24
//					< totalDayOfWork) {
					//Updated by NDTHO.2012.03.01
					Hours.hoursBetween(input, file.getOutputDate()).getHours()).doubleValue()/24
					< (totalDayOfWork - 1)) {
				return false;
			}
		}
		return true;
	}
	
	public Double getTotalDayOfWork(){
		return totalDayOfWork;
	}

	@Override
	protected void setSaveMessage() {
		ActionContext.getContext().getSession()
				.put("message", getText("file.saved"));
	}

	@Override
	protected void setDeleteMessage() {
		ActionContext.getContext().getSession()
				.put("message", getText("file.deleted"));
	}
	
	private String fileId;
	private String sender;
	
	public String getFileId() {
		return fileId;
	}

	public void setFileId(String fileId) {
		this.fileId = fileId;
	}

	public String getSender() {
		return sender;
	}

	public void setSender(String sender) {
		this.sender = sender;
	}

	@Override
	public String search() throws Exception {
		if (log.isDebugEnabled()) {
			log.debug("entering 'search' method");
		}
		Date f = StringUtils.isEmpty(fromDate) ? null : DateUtils.parseDate(
				fromDate, new String[] { getText("date.format") });
		Date t = StringUtils.isEmpty(toDate) ? null : DateUtils.parseDate(
				toDate, new String[] { getText("date.format") });
		
		ExtendedPaginatedList paginatedList = paginateListFactory
								.getPaginatedListFromRequest(ServletActionContext.getRequest());
		
		fileList = ((FileManager) mgr).search(NumberUtils.toInt(type), 
												NumberUtils.toLong(departmentId), 
												NumberUtils.toLong(fileStatusId), 
												NumberUtils.toLong(fieldId), 
												NumberUtils.toLong(cateId), 
												f, t, fileId, sender, paginatedList);
		
		ServletContext servletContext = ServletActionContext.getServletContext();
		
		servletContext.setAttribute(WebConstants.SEARCH_DEPARTMENT, departmentId);
		servletContext.setAttribute(WebConstants.SEARCH_STATUS, fileStatusId);
		servletContext.setAttribute(WebConstants.SEARCH_FIELD, fieldId);
		servletContext.setAttribute(WebConstants.SEARCH_CATEGORY, cateId);
		servletContext.setAttribute(WebConstants.SEARCH_FROM, fromDate);
		servletContext.setAttribute(WebConstants.SEARCH_TO, toDate);
		servletContext.setAttribute(WebConstants.SEARCH_FILEID, fileId);
		servletContext.setAttribute(WebConstants.SEARCH_SUBMITER, sender);
		
		return SUCCESS;
	}

	
	@Override
	public String save() {
		if (log.isDebugEnabled()) {
            log.debug("entering 'save' method");
        }
        
        entity = getEntity();
        FileStatus fs = new FileStatus();
        fs.setId(Long.valueOf(File.BEGIN));
        entity.setFileStatus(fs);
        
        ((FileManager)mgr).addFileMgrToFile(entity, fmgr);
        setSaveMessage();
        return SUCCESS;
	}
	
	/**
	 * Load file in 'begin' status
	 * @return
	 */
	public String fileByStatus() {
		if (log.isDebugEnabled()) {
            log.debug("entering 'fileByStatus' method");
        }
		
		ExtendedPaginatedList paginatedList = paginateListFactory.getPaginatedListFromRequest(ServletActionContext.getRequest());
		
		fileList = ((FileManager)mgr).findByStatus(NumberUtils.toInt(type), paginatedList);
        return SUCCESS;
	}
	
	@Override
	public String edit() throws Exception{
		
		if(this.id!=null && !"".equals(this.id)){
			entity = this.mgr.get(this.id);
			Set<FileManagement> lstFileMgr = entity.getFileManagements();
			for (Iterator<FileManagement> iterator = lstFileMgr.iterator(); iterator.hasNext();) {
				FileManagement object = iterator.next();
				if(object.getViewStatus() == null || !object.getViewStatus()) object.setViewStatus(true);
				this.fileMgrManager.save(object);
			}
			setTotalOverStep(lstFileMgr.size());
			
			ableToNextStep = ((FileManager)mgr).isAbleToNextStep(this.id, username);
			try {
				
				currentStep = fileMgrManager.getCurrentStep(this.id);
			} catch (Exception e) {
				// TODO: handle exception
				e.printStackTrace();
				ActionContext.getContext().getSession()
				.put("message", getText("D\u1EEF li\u1EC7u li\u00EAn quan \u0111\u1EBFn h\u1ED3 s\u01A1 b\u1ECB l\u1ED7i. H\u00E3y li\u00EAn h\u1EC7 v\u1EDBi Qu\u1EA3n tr\u1ECB vi\u00EAn."));
			}
		}
		
		return super.edit();
	}
	
	private Integer removeType;
	
	public String removeFile(){
		switch( removeType){
		
			case 1:
				fileMgr.removeAllFile();
				break;
				
			case 2:
				fileOnlineMgr.removeAllFile();
				break;

			case 3:
				fileMgr.removeAllDataTable();
				break;
			
		}

		ActionContext.getContext().getSession()
		.put("message", getText("H\u1ED3 s\u01A1 \u0111\u00E3 \u0111\u01B0\u1EE3c x\u00F3a th\u00E0nh c\u00F4ng"));
		
		return SUCCESS;
	}
	
	private Long form_file_id;
	private Integer form_type;
	public Integer getForm_type() {
		return form_type;
	}

	public void setForm_type(Integer form_type) {
		this.form_type = form_type;
	}

	private FileCapGPXDManager fileCapPhepXDMgr;
	private FileCapCCHNManager fileCapCCHNMgr;
	private FileCapLaiCCHNManager fileCapLaiCCHNMgr;
	private FileDieuChinhGPXDManager fileDieuChinhGPXDMgr;
	private FileGiaHanGPXDManager fileGiaHanCPXDMgr;
	private FileBoSungCCHNManager fileBoSungCCHNMgr;
	private FileCapCCMGBDSManager fileCapCCMGBDSMgr; 
	
	
	@Autowired
	public void setFileBoSungCCHNMgr(FileBoSungCCHNManager fileBoSungCCHNMgr) {
		this.fileBoSungCCHNMgr = fileBoSungCCHNMgr;
	}

	@Autowired
	public void setFileCapCCHNMgr(FileCapCCHNManager fileCapCCHNMgr) {
		this.fileCapCCHNMgr = fileCapCCHNMgr;
	}

	@Autowired
	public void setFileCapCCMGBDSMgr(FileCapCCMGBDSManager fileCapCCMGBDSMgr) {
		this.fileCapCCMGBDSMgr = fileCapCCMGBDSMgr;
	}
	
	@Autowired
	public void setFileCapLaiCCHNMgr(FileCapLaiCCHNManager fileCapLaiCCHNMgr) {
		this.fileCapLaiCCHNMgr = fileCapLaiCCHNMgr;
	}

	@Autowired
	public void setFileCapPhepXDMgr(FileCapGPXDManager fileCapPhepXDMgr) {
		this.fileCapPhepXDMgr = fileCapPhepXDMgr;
	}

	@Autowired
	public void setFileDieuChinhGPXDMgr(
			FileDieuChinhGPXDManager fileDieuChinhGPXDMgr) {
		this.fileDieuChinhGPXDMgr = fileDieuChinhGPXDMgr;
	}

	@Autowired
	public void setFileGiaHanCPXDMgr(FileGiaHanGPXDManager fileGiaHanCPXDMgr) {
		this.fileGiaHanCPXDMgr = fileGiaHanCPXDMgr;
	}
	
	/***
	 * Created on 30.07.2012 by NDTHO
	 * @return
	 * @throws Exception
	 */
	public String accept() throws Exception{
		
		String result = super.edit();
		this.file = new File();
		
		if (form_file_id != null) {
			switch(form_type)
			{
			case 1:
				  FileCapPhepXayDung fileCapPhepXayDung = fileCapPhepXDMgr.get(form_file_id);
				  
				  this.file.setSender(fileCapPhepXayDung.getChu_dau_tu());
				  this.file.setContactPhone(fileCapPhepXayDung.getDien_thoai());
				  this.file.setContactName(fileCapPhepXayDung.getNguoi_dai_dien());
				  this.file.setSubmitter(fileCapPhepXayDung.getChu_dau_tu());
				  this.file.setLocation(fileCapPhepXayDung.getLodat_dia_chi() + " - " +fileCapPhepXayDung.getLodat_duong()
						  + " - " +fileCapPhepXayDung.getLodat_phuong()
						  + " - " +fileCapPhepXayDung.getLodat_quan()
						  + " - " +fileCapPhepXayDung.getLodat_tp());
				  this.file.setAddress(fileCapPhepXayDung.getDia_chi_lien_he());
				  this.file.setSenderPhone(fileCapPhepXayDung.getDien_thoai());
				  this.file.setId(fileCapPhepXayDung.getFileCode());
				  this.file.setOrganization(fileCapPhepXayDung.getChu_dau_tu());

				  break;
				  
			  case 2:
				  FileCapCCHN fileCapCCHN = fileCapCCHNMgr.get(form_file_id);
				  this.file.setSender(fileCapCCHN.getHo_ten());
				  this.file.setContactName(fileCapCCHN.getHo_ten() );
				  this.file.setSubmitter(fileCapCCHN.getHo_ten() );
				  this.file.setAddress(fileCapCCHN.getDiachi_thuongtru() );
				  this.file.setId(fileCapCCHN.getFileCode() );
				  break;
				  
			  case 3:
				  FileCapLaiCCHN fileCapLaiCCHN = fileCapLaiCCHNMgr.get(form_file_id);
				  this.file.setSender(fileCapLaiCCHN.getContactName());
				  this.file.setContactName(fileCapLaiCCHN.getContactName() );
				  this.file.setSubmitter(fileCapLaiCCHN.getFullname() );
				  this.file.setAddress(fileCapLaiCCHN.getAddress() );
				  this.file.setId(fileCapLaiCCHN.getFileCode());
				  break;
				  
			  case 4:
				  FileDieuChinhGPXD fileDieuChinhGPXD = fileDieuChinhGPXDMgr.get(form_file_id);
				  this.file.setSender(fileDieuChinhGPXD.getHo_ten());
				  this.file.setContactName(fileDieuChinhGPXD.getHo_ten() );
				  this.file.setSubmitter(fileDieuChinhGPXD.getHo_ten() );
				  this.file.setAddress(fileDieuChinhGPXD.getDia_chi() 
						  + " - " + fileDieuChinhGPXD.getSo_nha()
						  + " - " + fileDieuChinhGPXD.getDuong()
						  + " - " + fileDieuChinhGPXD.getPhuong()
						  + " - " + fileDieuChinhGPXD.getQuan());
				  
				  this.file.setContactPhone(fileDieuChinhGPXD.getDien_thoai());
				  
				  this.file.setId(fileDieuChinhGPXD.getFileCode());
				  break;
				  
			  case 5:
				  FileGiaHanCPXD fileGiaHanCPXD = fileGiaHanCPXDMgr.get(form_file_id);
				  this.file.setSender(fileGiaHanCPXD.getHo_ten());
				  this.file.setContactName(fileGiaHanCPXD.getHo_ten() );
				  this.file.setSubmitter(fileGiaHanCPXD.getHo_ten() );
				  this.file.setAddress(fileGiaHanCPXD.getDia_chi() 
						  + " - " + fileGiaHanCPXD.getSo_nha()
						  + " - " + fileGiaHanCPXD.getDuong()
						  + " - " + fileGiaHanCPXD.getPhuong()
						  + " - " + fileGiaHanCPXD.getQuan());
				  
				  this.file.setId(fileGiaHanCPXD.getFileCode());
				  break;
				  
			  case 6:
				  FileBoSungCCHN fileBoSungCCHN = fileBoSungCCHNMgr.get(form_file_id);
				  this.file.setSender(fileBoSungCCHN.getHo_ten());
				  this.file.setContactName(fileBoSungCCHN.getHo_ten() );
				  this.file.setSubmitter(fileBoSungCCHN.getHo_ten() );
				  this.file.setAddress(fileBoSungCCHN.getDiachi_thuongtru() );
				  this.file.setId(fileBoSungCCHN.getFileCode());
				  break;
				  
			  case 7:
				  FileCapCCMGBDS fileCapCCMGBDS = fileCapCCMGBDSMgr.get(form_file_id);
				  this.file.setSender(fileCapCCMGBDS.getContactName());
				  this.file.setContactName(fileCapCCMGBDS.getContactName() );
				  this.file.setSubmitter(fileCapCCMGBDS.getFullname());
				  this.file.setAddress(fileCapCCMGBDS.getAddress() );
				  this.file.setId(fileCapCCMGBDS.getFileCode());
				  break;
			}
		}    
		return result;
	}
	
	
	private ExtendedPaginatedList fileList;
	
	public ExtendedPaginatedList getFileList() {
		return fileList;
	}

	public void setFileList(ExtendedPaginatedList fileList) {
		this.fileList = fileList;
	}

	private String title;
	private String type;
	
	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}
	

	public List<Exchange> getExchanges() {
		exchanges = ((FileManager)mgr).getExchangeByFileId(id, loggedUser.getId());
		return exchanges;
	}
	

	public List<WorkflowProcess> getWorkflowProcesses() {
		log.debug("enter getWorkflowProcesses......");
		workflowProcesses = wfpMgr.getWorkflowProcesses(entity.getCategory().getWorkflow().getId());
		return workflowProcesses;
	}

	public void setFileProcessVoucher(List<Object[]> fileProcessVoucher) {
		this.fileProcessVoucher = fileProcessVoucher;
	}
	
	private TimeWeekendManager weekendManager;
	private TimeHolidayManager holidayManager;
	
	@Autowired
	public void setHolidayManager(TimeHolidayManager holidayManager) {
		this.holidayManager = holidayManager;
	}
	
	@Autowired
	public void setWeekendManager(TimeWeekendManager weekendManager) {
		this.weekendManager = weekendManager;
	}
	
	/***
	 * Tinh toan thoi gian xu ly ho so tren moi buoc xu ly
	 * @return
	 */
	public List<Object[]> getFileProcessVoucher() {
		log.debug("enter getFileProcessVoucher......");
		fileProcessVoucher = ((FileManager)mgr).getFileProcessVoucher(id);
		
		for (int i = 0; i < fileProcessVoucher.size(); i++) {
			List<Object> tmp = new ArrayList<Object>();
			tmp.addAll(Arrays.asList(fileProcessVoucher.get(i)));
			
			//Dateformat: yyyy-mm-dd hh:mm:ss
			String orFromDate = (String)fileProcessVoucher.get(i)[10];
			String orToDate = (String)fileProcessVoucher.get(i)[11];
			DateTime fromDate = null;
			DateTime toDate = null;
			if(StringUtils.isNotEmpty(orFromDate)){
				fromDate = new DateTime(NumberUtils.toInt(orFromDate.substring(0,4)),
						NumberUtils.toInt(orFromDate.substring(5,7)), 
						NumberUtils.toInt(orFromDate.substring(8,10)),
						NumberUtils.toInt(orFromDate.substring(11,13)),
						NumberUtils.toInt(orFromDate.substring(14,16)));
				
			}

			if(StringUtils.isNotEmpty(orToDate)){
				toDate = new DateTime(NumberUtils.toInt(orToDate.substring(0,4)),
						NumberUtils.toInt(orToDate.substring(5,7)), 
						NumberUtils.toInt(orToDate.substring(8,10)),
						NumberUtils.toInt(orToDate.substring(11,13)),
						NumberUtils.toInt(orToDate.substring(14,16)));
				
			}

			// item[12]
			// Gan them ID cua buoc xl truoc va buoc xl hien tai => Phuc vu chuc nang Rollback
			if (i + 1 < fileProcessVoucher.size()) {
				tmp.add((fileProcessVoucher.get(i + 1)[1] == null && username.equals(fileProcessVoucher.get(i)[9])) ? 
						fileProcessVoucher.get(i + 1)[8] +" " + fileProcessVoucher.get(i)[8] : null);//[1] --> APPROVED_DATE --> [9] --> USERNAME [8] --> ID(FileManager)
			} else {
				tmp.add(null);
			}
			
			// Cho phep sua ngay ky duyet ho so; 1 - cho phep sua/ 0 - ko cho phep sua
			// item[13]
			if(username.equals(fileProcessVoucher.get(i)[9])){
				tmp.add("1");
			}else{
				tmp.add("0");
			}
			
			//Tinh toanh lam tron thoi gian xy ly ho so
			if(fromDate != null && toDate != null){
				
				Float totalDay = new Float(0);
				
				Float processTime = (Float)tmp.get(0);
				int workingday = getWorkingDays(fromDate, toDate);
				
				if(processTime > workingday) totalDay = new Float(workingday);
				else totalDay = processTime;
				
				log.debug(">>>>>>>>>>>ProcessTime: "+totalDay);
				log.debug(">>>>>>>>>>>Working days: "+workingday);
				
				totalDay = new Float(Math.round(totalDay));
				if(totalDay > 0)
					tmp.set(0, totalDay);
				else tmp.set(0, new Float(0));
				
			}
			
			Object[] result = tmp.toArray(new Object[]{});
			fileProcessVoucher.set(i, result);
		}
		
		return fileProcessVoucher;
	}
	
	public int getWorkingDays(DateTime fromdate, DateTime todate) {
		int result = 0;
		
		//period of time
		DateTime start = new DateMidnight().toDateTime();

		if(fromdate!=null) start = fromdate;
		log.debug("FROM DATE: "+fromdate + " >>>TO DATE: "+todate);
		
		//how many holidays are between the period of time 
		List<DateTime> lstDt = new ArrayList<DateTime>();
		List<TimeHoliday> timeHolidays = holidayManager.getList();
		for (TimeHoliday thday : timeHolidays) {
			if (thday.getRepeat()) {
				MutableDateTime mdt = new DateTime(thday.getHolidayDate()).toMutableDateTime();
				mdt.setYear(start.getYear());
				lstDt.add(mdt.toDateTime());
			} else {
				lstDt.add(new DateTime(thday.getHolidayDate()));
			}
		}
		
		//how many days off are between the period of time
		List<TimeWeekend> timeWeekends = weekendManager.getList();
		int[] dow = new int[]{DateTimeConstants.MONDAY, 
								DateTimeConstants.TUESDAY, 
								DateTimeConstants.WEDNESDAY, 
								DateTimeConstants.THURSDAY, 
								DateTimeConstants.FRIDAY, 
								DateTimeConstants.SATURDAY,
								DateTimeConstants.SUNDAY}; 
		List<Integer> dayOffs = new ArrayList<Integer>();
		for (TimeWeekend tw : timeWeekends) {
			for (int i = 0; i < dow.length; i++) {
				if (dow[i] == tw.getDay_id()) {
					dayOffs.add(dow[i]);
				}
			}
		}
		
		Collections.sort(dayOffs);
		
		
		DateTime tmp = start;
		for (;true;) {
			if(todate.getDayOfWeek() == tmp.getDayOfWeek() && todate.getDayOfMonth() == tmp.getDayOfMonth() && todate.getMonthOfYear() == tmp.getMonthOfYear())
				break;
			
			tmp = tmp.plusDays(1);
			System.out.print("tmp = " + tmp.toString("dd/MM/yyyy") + " " + tmp.toString("E"));
			
			boolean dayOffInTheWeek = false;
			boolean dayOffInTheHoliday = false;
			//day of week
			for (Integer dayOff : dayOffs) {
				if (tmp.getDayOfWeek() == dayOff) {
					//System.out.print(" ########## tmp.getDayOfWeek() == dayOff : " + (tmp.getDayOfWeek() == dayOff));
					dayOffInTheWeek = true;
					break;
				}
			}
			
			//day, month
			for (DateTime dt : lstDt) {
				if (dt.getDayOfMonth() == tmp.getDayOfMonth() && dt.getMonthOfYear() == tmp.getMonthOfYear()) {
					dayOffInTheHoliday = true;
				}
			}
			
			if (!dayOffInTheWeek && !dayOffInTheHoliday) result++;
			
 		}
		
		return result;
	}

	@Autowired
	public void setGroupMgr(GroupManager groupMgr) {
		this.groupMgr = groupMgr;
	}

	public Integer getMaxPosition() {
		Workflow workflow = ((FileManager)mgr).get(id).getCategory().getWorkflow();
		//return workflowMgr.getMaxPosition(workflow.getId());
		return (workflow==null? 0 : workflowMgr.getMaxPosition(workflow.getId()));
	}

	public void setDepartmentId(String departmentId) {
		this.departmentId = departmentId;
	}

	public String getDepartmentId() {
		return departmentId;
	}

	public void setFileStatusId(String fileStatusId) {
		this.fileStatusId = fileStatusId;
	}

	public String getFileStatusId() {
		return fileStatusId;
	}
	
	/**
	 * roll back functionality
	 * @return
	 */
	public String rollback() {
		fileMgrManager.rollback(getCurrentStepId(), getPreviousStepId());
		if (!StringUtils.isEmpty(rollbackSuccessfulMessage)) {
        	ActionContext.getContext().getSession()
						.put("message", getText(getRollbackSuccessfulMessage()));
        }
		return SUCCESS;
	}
	
	private Long currentStepId;
	private Long previousStepId;
	private String rollbackSuccessfulMessage;
	
	public String getRollbackSuccessfulMessage() {
		return rollbackSuccessfulMessage;
	}

	public void setRollbackSuccessfulMessage(String rollbackSuccessfulMessage) {
		this.rollbackSuccessfulMessage = rollbackSuccessfulMessage;
	}

	public Long getCurrentStepId() {
		return currentStepId;
	}

	public void setCurrentStepId(Long currentStepId) {
		this.currentStepId = currentStepId;
	}

	public Long getPreviousStepId() {
		return previousStepId;
	}

	public void setPreviousStepId(Long previousStepId) {
		this.previousStepId = previousStepId;
	}
	
	public boolean isAbleToNextStep(){
		return ableToNextStep;
	}
	
	private Integer currentStep;
	public Integer getCurrentStep() {
		return currentStep;
	}

	public void setCurrentStep(Integer currentStep) {
		this.currentStep = currentStep;
	}

	public void setGroupIdToExchange(String groupIdToExchange) {
		this.groupIdToExchange = groupIdToExchange;
	}

	public String getGroupIdToExchange() {
		
		// fieldID has selected on form
		if (StringUtils.isEmpty(groupIdToExchange) && entity!= null && entity.getId() != null) {
			return groupIdToExchange = entity.getCategory().getField().getDepartment().getId().toString();
		}
		// Load the first time enter form
		else{
			groupIdToExchange = loggedUser.getDepartment().getId().toString();
		}
		
		return groupIdToExchange;
	}
	public String getGroupIdToTransfer() {
		
		// fieldID has selected on form
		if (StringUtils.isEmpty(groupIdToTransfer) && entity!= null && entity.getId() != null) {
			return groupIdToTransfer = entity.getCategory().getField().getDepartment().getId().toString();
		}
		// Load the first time enter form
		else{
			groupIdToTransfer = loggedUser.getDepartment().getId().toString();
		}
		
		return groupIdToExchange;
	}
	
	
	@Autowired
	public void setUserManager(UserManager userManager) {
		this.userManager = userManager;
	}

	public void setGroupIdToTransfer(String groupIdToTransfer) {
		this.groupIdToTransfer = groupIdToTransfer;
	}

	public void setListAttachFile(List<AttachFileDetail> listAttachFile) {
		this.listAttachFile = listAttachFile;
	}

	public List<AttachFileDetail> getListAttachFile() {
		listAttachFile = new ArrayList<AttachFileDetail>();
		log.debug("--Enter method getListAttachFile...");
		List<AttachFileDetail> selectedAttachFiles = new ArrayList(entity.getAttachFileDetails()); 
		
			//this.fileMgr.getAttachFileDetailByFileId(getId());
		log.debug("--ListAttachedFile: "+selectedAttachFiles.size());
		List<AttachFile> lstAttachFiles = new ArrayList<AttachFile>();
			lstAttachFiles = this.attachFileManager.getByCatIdAndCatTypeId(Long.parseLong(getCateId()),entity.getCategoryType().getId());
		
		for (Iterator iterator = lstAttachFiles.iterator(); iterator.hasNext();) {
			boolean added = false;
			AttachFile attachFile = (AttachFile) iterator.next();
			log.debug("--Checking file..."+attachFile.getAttachFileName());
			
			for (Iterator iterator2 = selectedAttachFiles.iterator(); iterator2.hasNext();) {
				try {

					log.debug("========Checking...=========");
					
					AttachFileDetail attachFileDetail = (AttachFileDetail) iterator2.next();
					if(attachFile.getId() == attachFileDetail.getAttachFile().getId()){
						listAttachFile.add(attachFileDetail);
						log.debug("========Add file: "+attachFile.getAttachFileName());
						added = true;
						
					}
					//if(added) continue;
					
				} catch (Exception e) {
					// TODO: handle exception
					e.printStackTrace();
				}
			}
			
			if(added == false){
				AttachFileDetail attDetail = new AttachFileDetail();
				attDetail.setAttachFile(attachFile);
				attDetail.setNumberOfcopy(attachFile.getNumberOfCopy());
				
				listAttachFile.add(attDetail);
			}
			
		}
		return listAttachFile;
	}

	public void setListAttachByFile(List<AttachFileDetail> listAttachByFile) {
		this.listAttachByFile = listAttachByFile;
	}

	public List<AttachFileDetail> getListAttachByFile() {
		
		return listAttachByFile = this.fileMgr.findAttachFileDetailByFileId(getId());
	}


	public void setForm_file_id(Long form_file_id) {
		this.form_file_id = form_file_id;
	}

	public Long getForm_file_id() {
		return form_file_id;
	}

	public void setRemoveType(Integer removeType) {
		this.removeType = removeType;
	}

	public Integer getRemoveType() {
		return removeType;
	}

	public void setFileOnlineMgr(FileCapGPXDManager fileOnlineMgr) {
		this.fileOnlineMgr = fileOnlineMgr;
	}

	public FileCapGPXDManager getFileOnlineMgr() {
		return fileOnlineMgr;
	}


	public void setTotalOverStep(int totalOverStep) {
		this.totalOverStep = totalOverStep;
	}

	public int getTotalOverStep() {
		return totalOverStep;
	}
}
